﻿using CefGlue.Avalonia.Handlers;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
using TouchSocket.Rpc;
using TouchSocket.WebApi;

namespace CefGlue.Avalonia.Http
{

    public class TouchWebApiServer: RpcServer
    {
        static ConcurrentDictionary<int, ObjectTypeInfo> CallObjMap = new ConcurrentDictionary<int, ObjectTypeInfo>();
        static ConcurrentDictionary<string, MethodInfo> CallMethodMap = new ConcurrentDictionary<string, MethodInfo>();
        [Router(CommonConst.WebapiPath)]
        [WebApi(HttpMethodType.POST)]
        public JavsscriptResultObject DoExecute(JavascriptCallObject javascriptCallObject)
        {   
            int objectId = javascriptCallObject.ObjectId;
            string objectTypeName = javascriptCallObject.ObjectType;
            string methodName = javascriptCallObject.MethodName;
            string assemblyName = javascriptCallObject.AssemblyName;
            Dictionary<int, object> CallParams = javascriptCallObject.CallParams;
            ObjectTypeInfo callObject = null;
            Type callObjType = null;
            if (!CallObjMap.TryGetValue(objectId, out callObject))
            {
                Assembly assembly = Assembly.Load(assemblyName);
                callObjType = assembly.GetType(objectTypeName, true, true);
                object Object = Activator.CreateInstance(callObjType);
                callObject = new ObjectTypeInfo() { Object = Object, Type = callObjType };
                CallObjMap.AddOrUpdate(objectId, (id) => { return callObject; }, (id, o) => { return callObject; });
            }
            if (callObject == null)
            {
                return new JavsscriptResultObject { Message = $"对象\"{objectTypeName}\"不存在", IsSuccess = false };
            }
            callObjType = callObject.Type;
            string methodKey = $"{objectId}-{methodName}";
            if (!CallMethodMap.TryGetValue(methodKey, out MethodInfo callMethod))
            {
                callMethod = callObjType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                CallMethodMap.AddOrUpdate(methodKey, (id) => { return callMethod; }, (id, o) => { return callMethod; });
            }
            if (callMethod == null)
            {
                return new JavsscriptResultObject { Message = $"对象\"{objectTypeName}\"不存在", IsSuccess = false };
            }
            int paramCount = CallParams.Count;
            var paramTypeList = callMethod.GetParameters();
            object[] paramList = new object[paramCount];
            for (int i = 0; i < paramCount; i++)
            {
#pragma warning disable CS0168 // 声明了变量，但从未使用过
                try
                {
                    paramList[i] = Convert.ChangeType(CallParams[i]?.ToString(), paramTypeList[i].ParameterType);
                }
                catch (Exception ex)
                {
                    paramList[i] = Newtonsoft.Json.JsonConvert.DeserializeObject(CallParams[i]?.ToString(), paramTypeList[i].ParameterType);
                }
#pragma warning restore CS0168 // 声明了变量，但从未使用过
            }
            object returnObject = callMethod.Invoke(callObject.Object, paramList);
            Type returnType = callMethod.ReturnParameter.ParameterType;
            object actualreturnObject = null;

            if (returnType.BaseType == typeof(Task))
            {
                object realReturnValue = returnType.GetProperty("Result").GetValue(returnObject);
                actualreturnObject = realReturnValue;
            }
            else
            {
                actualreturnObject = returnObject;
            }
            return new JavsscriptResultObject() { Message = "", Object = actualreturnObject, IsSuccess = true };
        }
    }
}
